package com.triumphxx.datadeal;


import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

public class ListMatcher {

    static class ObjectA {
        String a;
        String b;
        Date c; // 日期字段，需要非空处理
        int numericField1;
        double numericField2;
        String otherField;

        public ObjectA(String a, String b, Date c, int n1, double n2, String other) {
            this.a = a;
            this.b = b;
            this.c = c ;
            this.numericField1 = n1;
            this.numericField2 = n2;
            this.otherField = other;
        }

        @Override
        public String toString() {
            return String.format(
                    "[a=%s, b=%s, c=%s, num1=%d, num2=%.1f, other=%s]",
                    a, b, (c != null ? new SimpleDateFormat("yyyy-MM-dd").format(c) : "null"), numericField1, numericField2, otherField
            );
        }
    }

    // 分组键
    static class GroupKey {
        String a;
        String b;

        public GroupKey(String a, String b) {
            this.a = a;
            this.b = b;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            GroupKey groupKey = (GroupKey) o;
            return Objects.equals(a, groupKey.a) &&
                    Objects.equals(b, groupKey.b);
        }

        @Override
        public int hashCode() {
            return Objects.hash(a, b);
        }
    }

    // 匹配候选对象
    static class MatchCandidate implements Comparable<MatchCandidate> {
        long dateDiff;
        int index1;
        int index2;

        public MatchCandidate(long dateDiff, int index1, int index2) {
            this.dateDiff = dateDiff;
            this.index1 = index1;
            this.index2 = index2;
        }

        @Override
        public int compareTo(MatchCandidate other) {
            return Long.compare(this.dateDiff, other.dateDiff);
        }
    }

    public static List<ObjectA> matchAndMerge(
            List<ObjectA> list1,
            List<ObjectA> list2
    ) {
        // 1. 按分组键(a,b)分组
        Map<GroupKey, List<ObjectA>> group1 = list1.stream()
                .collect(Collectors.groupingBy(obj -> new GroupKey(obj.a, obj.b)));

        Map<GroupKey, List<ObjectA>> group2 = list2.stream()
                .collect(Collectors.groupingBy(obj -> new GroupKey(obj.a, obj.b)));

        // 2. 获取所有唯一分组键
        Set<GroupKey> allKeys = new HashSet<>();
        allKeys.addAll(group1.keySet());
        allKeys.addAll(group2.keySet());

        List<ObjectA> result = new ArrayList<>();

        // 3. 处理每个分组
        for (GroupKey key : allKeys) {
            List<ObjectA> groupList1 = group1.getOrDefault(key, Collections.emptyList());
            List<ObjectA> groupList2 = group2.getOrDefault(key, Collections.emptyList());

            // 处理当前分组
            processGroup(groupList1, groupList2, result);
        }

        return result;
    }

    private static void processGroup(
            List<ObjectA> group1,
            List<ObjectA> group2,
            List<ObjectA> result
    ) {
        // 4. 创建匹配候选队列
        PriorityQueue<MatchCandidate> queue = new PriorityQueue<>();

        // 5. 标记已匹配项
        boolean[] matched1 = new boolean[group1.size()];
        boolean[] matched2 = new boolean[group2.size()];

        // 6. 计算所有可能的匹配对
        for (int i = 0; i < group1.size(); i++) {
            ObjectA obj1 = group1.get(i);
            for (int j = 0; j < group2.size(); j++) {
                ObjectA obj2 = group2.get(j);
                if (obj1.c == null || obj2.c == null) {
                    continue;
                }
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(obj2.c);
                calendar.add(Calendar.YEAR, -1); // 年份减1
                Date date2=  calendar.getTime();
                long diff = Math.abs(obj1.c.getTime() - obj2.c.getTime());
                //当单的终止的日一定大于续保单 且当单生效日大于续保单终止日
                if ((obj2.c.after(obj1.c) && date2.after(obj1.c)) || (date2.compareTo(obj1.c)==0)){
                    queue.add(new MatchCandidate(diff, i, j));
                }else {
                    queue.add(new MatchCandidate(diff, i, j));
                }
            }
        }

        // 7. 处理最佳匹配
        while (!queue.isEmpty()) {
            MatchCandidate candidate = queue.poll();
            int i = candidate.index1;
            int j = candidate.index2;

            // 检查是否已被匹配
            if (!matched1[i] && !matched2[j]) {
                ObjectA obj1 = group1.get(i);
                ObjectA obj2 = group2.get(j);

                // 合并对象（包含日期非空处理）
                ObjectA merged = mergeObjects(obj1, obj2);
                result.add(merged);

                // 标记为已匹配
                matched1[i] = true;
                matched2[j] = true;
            }
        }

        // 8. 添加未匹配项
        for (int i = 0; i < matched1.length; i++) {
            if (!matched1[i]) {
                result.add(group1.get(i));
            }
        }

        for (int j = 0; j < matched2.length; j++) {
            if (!matched2[j]) {
                result.add(group2.get(j));
            }
        }
    }

    // 合并
    private static ObjectA mergeObjects(ObjectA obj1, ObjectA obj2) {
        return new ObjectA(
                obj1.a,
                obj1.b,
                obj1.c,
                Math.max(obj1.numericField1, obj2.numericField1),
                Math.max(obj1.numericField2, obj2.numericField2),
                obj1.otherField  // 保留第一个对象的非数值字段
        );
    }

    public static void main(String[] args) {
        // 创建测试数据
        //生效日
        Date today = new Date();
        //终止日
        Date afterYear = new Date(today.getTime() + 365 * 24 * 3600 * 1000);
        Date yesterday = new Date(afterYear.getTime() - 24 * 3600 * 1000);
        Date tomorrow = new Date(afterYear.getTime() + 24 * 3600 * 1000);
        Date beforeYesterday = new Date(afterYear.getTime() - 48 * 3600 * 1000);

        List<ObjectA> list1 = Arrays.asList(
//                new ObjectA("A", "B1", yesterday, 10, 5.5, "Text1-1"),//续保单
//                new ObjectA("A", "B2", yesterday, 20, 8.3, "Text1-2"),//续保单
//                new ObjectA("A", "B3", yesterday, 30, 12.0, "Text1-3"),//续保单
//
//                new ObjectA("A", "B1", tomorrow, 10, 5.5, "Text1-1"),//续保单
//                new ObjectA("A", "B2", tomorrow, 20, 8.3, "Text1-2"),//续保单
//                new ObjectA("A", "B3", tomorrow, 30, 12.0, "Text1-3"),//续保单

                new ObjectA("A", "B1", today, 88, 35, "Text1-1a"),
                new ObjectA("A", "B2", today, 5, 0.5, "Text1-2b"),
                new ObjectA("A", "B3", today, 1, 15.2, "Text1-3c"),

//                new ObjectA("A", "B1", beforeYesterday, 10, 5.5, "Text1-4"),
//                new ObjectA("A", "B2", beforeYesterday, 20, 8.3, "Text1-5"),
//                new ObjectA("A", "B3", beforeYesterday, 30, 12.0, "Text1-6"),
                new ObjectA("A", "B4", beforeYesterday, 40, 15.0, "Text1-10"),//其他单险种
                new ObjectA("A", "B5", null, 50, 18.0, "Text1-11")
        );
        List<ObjectA> list2 = Arrays.asList(
                new ObjectA("A", "B1", afterYear, 15, 7.2, "Text2-13"),
                new ObjectA("A", "B2", afterYear, 18, 9.1, "Text2-14"),
                new ObjectA("A", "B3", afterYear, 25, 11.5, "Text2-15")
        );

        // 执行匹配合并
        List<ObjectA> result = matchAndMerge(list1, list2);

        // 打印结果
        System.out.println("匹配合并结果(" + result.size() + "):");
        result.forEach(System.out::println);

    }
}